-- Radical by Basil Voronkov
-- Module 'rooms'
---------------------------------------------
-- This module implements various high level
-- rooms based on the 'gameroom' primitive defined
-- in 'engine' module.
require "theme"
require "lib/engine"
require "lib/const"
require "lib/table"
require "lib/inventory"

rooms = {};

function rooms.init()  
  sys_blackroom = blackroom(500,5);
  sys_blackroom2 = blackroom(500,30);
  sys_blackroom3 = blackroom(2000,5);
  sys_blackroom4 = blackroom(2000,30);
  sys_gameover = gameover_room(load_checkpoint);
end

function gameover_room(o)
  return scene {
     tile       = { const.path.gfx.."gameover.jpg", 405, 260 }
    ,nohud      = true
    ,enter      = function(s)
                    _activeitem = nil;
                    mute_sound();
                    stop_music();
                  end
    ,localact   = o
    ,alwaysdsc  = true
    ,dsc        = "{localact|Загрузить последнюю контрольную точку}"
    ,bounds     = { 350, 520 }
  }
end

function blackroom(time,fading)
  return pause {
     time       = time
    ,fading     = fading
    ,next       = function(s)
                    ref(s._transfer).tmpdsc = s._transferdsc;
                    walk(s._transfer);
                  end
  }
end

function pause(o)
  return engine.gameroom {
     tile       = o.tile
    ,noclean    = o.noclean
    ,fading     = o.fading
    ,fps        = 1000/o.time
    ,entered    = o.entered
    ,enter      = o.enter
    ,exit       = o.exit
    ,bounds     = o.bounds
    ,dsc        = o.dsc
    ,hidemenu   = true
    ,ondrawbg   = o.ondrawbg
    ,ondraw     = o.ondraw
    ,onclick    = o.onclick
    ,ontimer    = function(s)
                    if s.tilecache ~= nil then
                      sprite.free(s.tilecache);
                      s.tilecache = nil;
                    end
                    if is_function(o.next) then
                      o.next(s);
                    else
                      ref(o.next).tmpdsc = nil;
                      walk(o.next);
                    end
                  end
  }
end

function scene(o)
  local dsc = o.dsc;
  o.fps         = nvl(o.fps,20);
  o.showdsc     = function(s)
                    return s.alwaysdsc or not s._seen;
                  end
  o.onclickr    = function(s)
                    inventory.clearitem();
                    refresh();
                  end
  return inventory.room(navigation.room(engine.gameroom(o)));
end

function cutscene(o)
  local dsc = o.dsc;
  o.fps         = nvl(o.fps,20);
  o.dsc         = function(s)
                    local ret = rcall(dsc,s);
                    if ret ~= nil then
                      return ret.." ARR";
                    end
                  end
  o.onclick     = function(s)
                    if not is_function(o.next) then
                      ref(o.next).tmpdsc=nil;
                      walk(o.next);
                    else
                      o.next(s);
                    end
                  end
  return engine.gameroom(o);
end

function timerroom(o)
  local ret = {
     fps        = 20
    ,hidemenu   = true
    ,fading     = 0
    ,dsc        = o.dsc
    ,obj        = o.obj
    ,bounds     = nvl(o.bounds, { nil, 500 })
    ,x          = 280
    ,y          = 82
    ,ontimer    = function(s,x,y)
                    if s.sfn == nil then
                      s.sfn = 0;
                    end
                    s.sfn = s.sfn + 1;
                    if math.mod(s.sfn, 20) == 0 then
                      local sec = s.sfn / 20;
                      if sec - 2 == o.seconds then
                        s.sfn = nil;
                        s.lastsec = nil;
                        walk(o.next);
                        return;
                      end
                      if s.lastsec == nil or sec ~= s.lastsec then
                        play_sound("tick");
                        drawing.clean(s.pic, s.x, s.y, 400, 315);
                        local spr = sprite.load(const.path.gfx.."game/common/"..tostring(sec-1)..".jpg");
                        sprite.copy(spr, s.pic, s.x, s.y);
                        sprite.free(spr);
                        s.lastsec = sec;
                      end
                    elseif math.mod(s.sfn,10) == 0 then
                      drawing.clean(s.pic, s.x, s.y, 400, 315);
                    end
                  end
  }
  return inventory.room(engine.gameroom(ret));
end

function slideup(o)
  return engine.gameroom {
     fps        = o.fps
    ,bounds     = o.bounds
    ,dsc        = o.dsc
    ,fading     = o.fading
    ,hidemenu    = true
    ,ontimer    = function(s,x,y)
                    if s._tiley == nil then
                      s._tiley = o.y;
                    end
                    local endy = o.endy;
                    if endy == nil and s.tileh ~= nil then
                      endy = const.picheight-20 - s.tileh;
                    end
                    if s.tilecache ~= nil and s._tiley < endy then
                      sprite.free(s.tilecache);
                      s.tilecache = nil;
                      s._tiley = nil;
                      if is_function(o.next) then
                        o:next();
                      else
                        walk(o.next);
                      end
                      return;
                    end
                    if s.tilecache == nil then
                      s.tilecache = sprite.load(o.tile);
                      s.tilew,s.tileh = sprite.size(s.tilecache);
                    end
                    sprite.copy(s.tilecache, s.pic, o.x, s._tiley);
                    s._tiley = s._tiley - o.step;
                  end
  }  
end

function slidedown(o)
  return engine.gameroom {
     fps        = o.fps
    ,bounds     = o.bounds
    ,dsc        = o.dsc
    ,fading     = o.fading
    ,ontimer    = function(s,x,y)
                    if s.tilecache ~= nil and s._tiley > o.y then
                      sprite.free(s.tilecache);
                      s.tilecache = nil;
                      s._tiley = nil;
                      if is_function(o.next) then
                        o:next();
                      else
                        walk(o.next);
                      end
                      return;
                    end
                    if s.tilecache == nil then
                      s.tilecache = sprite.load(o.tile);
                      s.tilew,s.tileh = sprite.size(s.tilecache);
                    end
                    if s._tiley == nil then
                      if o.starty == nil then
                        s._tiley = const.picheight - s.tileh;
                      else
                        s._tiley = o.starty
                      end
                    end
                    drawing.clean(s.pic, o.x, s._tiley - o.step, s.tilew, o.step);
                    sprite.copy(s.tilecache, s.pic, o.x, s._tiley);
                    s._tiley = s._tiley + o.step;
                  end
  }  
end

function tremor(o)
  return engine.gameroom {
     fps        = o.fps
    ,fading     = o.fading
    ,ontimer    = function(s,x,y)
                    if s.tilecache ~= nil and s._tiley==o.y-o.step and s._done then
                      sprite.free(s.tilecache);
                      s.tilecache = nil;
                      s._tiley = nil;
                      s._done = nil;
                      walk(o.next);
                      return;
                    end
                    if s.tilecache == nil then
                      s.tilecache = sprite.load(o.tile);
                      s.tilew,s.tileh = sprite.size(s.tilecache);
                    end
                    
                    if s._tiley == nil then
                      s._tiley = o.y
                    end
                    
                    if s._tiley == o.y+o.amp then
                      s._done = true;
                    end
                    
                    local step = o.step;
                    if s._done then
                      step = -step;
                    end
                    
                    drawing.clean(s.pic, o.x, s._tiley + step, s.tilew, o.step);
                    sprite.copy(s.tilecache, s.pic, o.x, s._tiley);
                    s._tiley = s._tiley + step;
                  end
  }  
end

function slideright(o)
  return engine.gameroom {
     fps        = o.fps
    ,hidemenu   = true
    ,fading     = o.fading
    ,bounds     = o.bounds
    ,dsc        = o.dsc
    ,ontimer    = function(s,x,y)
                    if s.finita then
                      return;
                    end
                    if s._tilex == nil then
                      s._tilex = o.x;
                    end
                    if s.tilecache ~= nil and s._tilex == o.endx+o.step then
                      sprite.free(s.tilecache);
                      s.tilecache = nil;
                      s._tilex = nil;
                      if o.next ~= nil then
                        walk(o.next);
                      else
                        s.finita = true;
                      end
                      return;
                    end
                    if s.tilecache == nil then
                      s.tilecache = sprite.load(o.tile);
                      s.tilew,s.tileh = sprite.size(s.tilecache);
                    end
                    sprite.copy(s.tilecache, s.pic, s._tilex, o.y);
                    s._tilex = s._tilex + o.step;
                  end
  }
end

function anim(o)
  return engine.gameroom {
     fps        = nvl(o.fps,10)
    ,fading     = 0
    ,snd        = o.snd
    ,cycles     = nvl(o.cycles,1)
    ,ontimer    = function(s,x,y)
                    if s._cyc == nil then
                      s._cyc = 0;
                    end
                    if s._pause then
                      if s._pausecc == nil then
                        s._pausecc = 0;
                      end
                      s._pausecc = s._pausecc + 1;
                      if s._pausecc == o.pause then
                        s._pausecc = nil;
                        s._pause = nil;
                        if s._cyc == s.cycles then
                          s._cyc = nil;
                          walk(o.next);
                        end
                      end
                      return;
                    end
                    if s._frame ~= nil and s._frame > table.len(o.frames) then
                      s._cyc = s._cyc + 1;
                      s._frame = nil;
                      if s._cyc == s.cycles and o.pause == nil then
                        s._cyc = nil;
                        s._pausecc = nil;
                        s._pause = nil;
                        walk(o.next);
                        return;
                      elseif o.pause ~= nil then
                        s._pause = true;
                        return;
                      end
                    end
                    if s._frame == nil then
                      s._frame = 1;
                      if s.snd ~= nil then
                        play_sound(s.snd);
                      end
                    end
                    local frame = o.frames[s._frame];
                    local spr = sprite.load(frame);
                    sprite.copy(spr, s.pic, o.x, o.y);
                    sprite.free(spr);
                    s._frame = s._frame + 1;
                  end
  }
end

function staticitem(o)
  local act = o.act;
  local dsc = o.dsc;
  local disable = o.disable;
  o.dsc         = function(s)
                    local dis = rcall(disable,s);
                    if not dis and (not s._seen or not s.showonce) then
                      return rcall(dsc,s);
                    else
                      return rcall(dsc,s):normalize();
                    end
                  end
  o.act         = function(s)
                    if _activeitem == nil then
                      s._seen = true;
                      if act ~= nil then
                        return rcall(act,s);
                      else
                        return "";
                      end
                    else
                      local ai = ref(_activeitem);
                      local ret = ai.use;
                      if is_function(ai.use) then
                        ret = ref(_activeitem):use(deref(s));
                      end
                      inventory.clearitem();
                      return ret;
                    end
                  end
  return engine.item(o);
end

function item(o)
  if o.activate == nil then
    o.activate  = function(s)
                    _activeitem = deref(s);
                    theme.set("scr.gfx.cursor.normal", rcall(o.img));
                    refresh();
                  end
  end
  o.take        = function(s)
                    if _activeitem == nil then
                      local dsc = rcall(o.tak,s);
                      if o.takcnd == nil or rcall(o.takcnd) then
                        remove(s);
                        inventory.add(s);
                      end
                      here().tmpdsc = dsc;
                      refresh();
                    else
                      local ai = ref(_activeitem);
                      local ret = ai.use;
                      if is_function(ai.use) then
                        ret = ref(_activeitem):use(deref(s));
                      end
                      inventory.clearitem();
                      return ret;
                    end
                  end
  o.act         = o.take;
  return engine.item(o);
end

function matroska(v)
  function safe_ret(b)
    if b == nil then
      return true;
    elseif is_function(b) then
      return b();
    else
      return b;
    end
  end
  return engine.item {
     _lvl       = 1
    ,nam        = ""
    ,levels     = v
    ,dsc        = function(s)
                    if s._lvl > table.len(s.levels) then
                      return nil;
                    else
                      return safe_ret(s.levels[s._lvl].dsc);
                    end
                  end
    ,act        = function(s)
                    local o = s.levels[s._lvl];
                    if o == nil then
                      return "";
                    end
                    o._seen = true;
                    s._lvl = s._lvl + 1;
                    return rcall(o.act, o);
                  end
  }
end

function xobj(dsc, act, once)
  return staticitem {
     nam        = "x03"
    ,dsc        = dsc
    ,act        = act
    ,showonce   = once
  }
end

function chapter(num,title,next,time,fading)
  return pause {
     time       = nvl(time,5000)
    ,fading     = nvl(fading,30)
    ,ondrawbg   = function(s,p)
                    local t1 = sprite.text(drawing.font(const.fontb, 16), "Глава "..tostring(num), "white");
                    sprite.draw(t1, p, (const.picwidth - sprite.size(t1))/2, 250);
                    sprite.free(t1);
                    
                    local t2 = sprite.text(drawing.font(const.fontb, 24), title, "white");
                    sprite.draw(t2, p, (const.picwidth - sprite.size(t2))/2, 275);
                    sprite.free(t2);
                    
                    return p;
                  end
    ,next       = next
  }
end

function text_tremor(txt,tx,ty,trem,fs,fc,fun)
  if trem == nil then
    trem = 8;
  end
  if fs == nil then
    fs = 18;
  end
  if fc == nil then
    fc = const.textcolor;
  end
  return function(s,x,y)
    if s.tilecache == nil then
      s.tilecache = sprite.text(drawing.font(const.fontb, fs), txt, fc);
      s.tilecache_w,s.tilecache_h = sprite.size(s.tilecache)
    end
    if s.oldx ~= nil then
      drawing.clean(s.pic, s.oldx, s.oldy, s.tilecache_w, s.tilecache_h);
    end
    local sh1,sh2 = rnd(trem), rnd(trem);
    s.oldx = tx+sh1;
    s.oldy = ty+sh2;
    sprite.copy(s.tilecache, s.pic, s.oldx, s.oldy);
    fun(s,x,y);
  end
end